package com.aleyn.router.plug.visitor

import com.aleyn.router.plug.data.HandleModel
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes.BIPUSH
import org.objectweb.asm.Opcodes.CHECKCAST
import org.objectweb.asm.Opcodes.NEW
import org.objectweb.asm.commons.InstructionAdapter


/**
 * @author: Aleyn
 * @date: 2023/7/20 15:06
 *
 * ASM MethodVisitor, 用于向 `LRouterGenerateImpl.registerIntercept` 方法中注入字节码。
 *
 * 这个类的核心任务是将在扫描阶段发现的所有拦截器 (`Interceptor`) 注册到 `LRouter` 中。
 * 它会遍历所有实现了 `LRouterInterceptor` 接口并被 `@Interceptor` 注解标记的类，
 * 然后为每个拦截器生成调用 `LRouter.addInterceptor` 方法的字节码。
 *
 * 此 Adapter 会在 `LRouterGenerateImpl.registerIntercept()` 方法中生成如下等效代码：
 * ```java
 * // 假设有一个 Interceptor: com.example.MyInterceptor, priority=7
 * LRouter.addInterceptor(7, new com.example.MyInterceptor());
 * // ... 对其他 Interceptor 重复此操作
 * ```
 *
 * @param api ASM API的版本。
 * @param methodVisitor 委托的下一个 MethodVisitor。
 * @param interceptClass 包含所有需要注册的拦截器信息的列表。
 */
class InterceptInstructAdapter(
    api: Int,
    methodVisitor: MethodVisitor,
    private val interceptClass: List<HandleModel.Intercept>?,
) : InstructionAdapter(api, methodVisitor) {

    /**
     * 在目标方法的代码开始处被调用。
     *
     * 这是实现字节码注入的关键位置。
     * 该方法会遍历 `interceptClass` 列表，为每个拦截器生成相应的注册代码。
     */
    override fun visitCode() {
        interceptClass?.forEach {
            // 加载优先级 (priority) 到操作数栈
            mv.visitIntInsn(BIPUSH, it.priority.toInt())
            // 创建 Interceptor 实例: new com.example.MyInterceptor()
            mv.visitTypeInsn(NEW, it.className)
            dup()
            // 调用其无参构造函数: <init>()
            invokespecial(it.className, "<init>", "()V", false)
            // 类型转换为 LRouterInterceptor
            mv.visitTypeInsn(CHECKCAST, "com/aleyn/router/core/LRouterInterceptor")
            // 调用静态方法 LRouter.addInterceptor(priority, instance)
            invokestatic(
                "com/aleyn/router/LRouter",
                "addInterceptor",
                "(BLcom/aleyn/router/core/LRouterInterceptor;)V",
                false
            )
        }
        super.visitCode()
    }

}